﻿#include <iostream>
#include <string>
using namespace std;

// 基类：_Person（带继承权限演示）
class _Person
{
public:
	void Print()
	{
		cout << "name:" << _name << endl;
		cout << "age:" << _age << endl;
	}
	// 修正补充：类内部（成员函数、友元）中，private和protected成员访问权限完全相同（均可直接访问）；
	// 类外部：两者均无法访问；核心区别在继承：子类能访问父类的protected成员，不能访问父类的private成员
protected:
	string _name = "peter"; // 姓名（子类可直接访问）
private:
	int _age = 18; // 年龄（子类不可直接访问，但可通过父类public成员函数间接访问，如Print()）
};

// 子类：_Student（public继承_Person）
class _Student : public _Person
{
public:
	void Print() {
		// 补充：父类private成员（_age）在子类对象内存中“存在”（切片可见），但子类代码无法直接访问；
		// 若需访问_age，可调用父类的public成员函数（如父类的Print()）间接获取
		cout << "子类访问父类protected成员_name：" << _name << endl;
		// cout << _age << endl; // 编译报错：父类private成员子类不可直接访问
	}
protected:
	int _stuid; // 学号（子类独有成员）
};

// 子类：_Teacher（public继承_Person）
class _Teacher : public _Person
{
protected:
	int _jobid; // 工号（子类独有成员）
};

// 测试_Person继承体系
void test_Person()
{
	_Student s;
	_Teacher t;
	s.Print();       // 子类Print()：仅输出_name
	t._Person::Print(); // 调用父类Print()：输出_name和_age（间接访问父类private成员）
}

// 基类和派生类对象赋值转换（切片规则）
void _Test()
{
	_Person p;
	_Student s;

	// 1. 子类对象可以赋值给父类对象/指针/引用（切片）
	// 补充：“切片”仅赋值父类部分成员，子类独有成员（如_stuid）会被舍弃，不会赋值给父类对象
	p = s; // 正确：p仅接收s的父类部分（_name、_age），_stuid被舍弃

		   // 补充：父类指针指向子类对象时，仅能访问父类成员（按指针类型解析接口），无法访问子类独有成员
	_Person* ptr = &s;
	ptr->Print(); // 正确：调用父类Print()，无法调用子类Print()或访问_stuid

				  // 引用与指针规则一致：仅能访问父类成员
	_Person& ref = s;
	ref.Print(); // 正确：调用父类Print()

				 // 2. 基类对象不能赋值给派生类对象
				 // s = p; // 编译报错：父类对象无法给子类对象赋值（子类成员无来源）

				 // 3. 基类指针强制转换为派生类指针（风险提示）
				 // 补充：C风格强制转换不安全！若ptr实际指向父类对象（非子类对象），后续访问子类独有成员会触发未定义行为；
				 // C++推荐：有虚函数时用dynamic_cast（安全检查），无虚函数且确认指向子类时用static_cast

}

// 继承中的作用域（同名成员隐藏/重定义）
class Person_Scope
{
protected:
	string _name = "小李子"; // 姓名（父类成员）
	int _num = 111;          // 身份证号（父类成员）
};

class Student_Scope : public Person_Scope
{
public:
	void Print()
	{
		cout << " 姓名:" << _name << endl; // 访问父类_name（无同名，直接访问）
										 // 补充：同名成员需加父类作用域访问，否则默认访问子类成员（作用域遮蔽规则）
		cout << " 身份证号:" << Person_Scope::_num << endl; // 访问父类_num
		cout << " 学号:" << _num << endl; // 访问子类_num（默认优先解析子类成员）
	}
protected:
	// 补充：子类与父类同名成员（变量/函数）构成“隐藏”（重定义），与参数列表无关；
	// 若为函数，即使参数不同，也会隐藏父类函数（非重载，重载要求同一作用域）
	int _num = 999; // 学号（子类成员，隐藏父类_num）
};

void Test_Person_Scope()
{
	Student_Scope s1;
	s1.Print();
	// 补充：若父类有同名函数void func()，子类有void func(int)，调用父类func需显式加作用域：
	// s1.Person_Scope::func(); // 正确调用父类无参func()
	// s1.func(10); // 正确调用子类有参func()
	// s1.func(); // 编译报错：子类func(int)隐藏父类func()，无匹配参数
}

// 继承中的构造/拷贝构造/赋值/析构（生命周期管理）
class Person
{
public:
	// 构造函数（带默认参数）
	Person(const char* name = "peter")
		: _name(name)
	{
		cout << "Person()" << endl;
	}

	// 拷贝构造函数
	Person(const Person& p)
		: _name(p._name)
	{
		cout << "Person(const Person& p)" << endl;
	}

	// 赋值运算符重载
	Person& operator=(const Person& p)
	{
		cout << "Person& operator=(const Person& p)" << endl;
		if (this != &p)
			_name = p._name;
		return *this;
	}

	// 析构函数
	~Person()
	{
		cout << "~Person()" << endl;
	}
protected:
	string _name; // 姓名
};

class Student : public Person
{
public:
	// 子类构造函数：必须初始化父类部分
	Student(const char* name, int num)
		: Person(name) // 显式调用父类有参构造（若父类无默认构造，必须显式调用）
		, _num(num)
	{
		cout << "Student()" << endl;
	}
	// 补充：若父类无默认构造（如无参构造/全缺省构造），子类构造函数必须显式调用父类有参构造；
	// 若父类有默认构造，子类不写则自动调用父类默认构造（但推荐显式调用，逻辑更清晰）

	// 子类拷贝构造函数
	Student(const Student& s)
		: Person(s) // 调用父类拷贝构造（利用赋值兼容规则：子类对象s可传给父类拷贝构造的Person&参数）
		, _num(s._num)
	{
		cout << "Student(const Student& s)" << endl;
	}
	// 补充：子类拷贝构造需手动初始化父类部分（调用父类拷贝构造），否则父类部分会调用默认构造（可能不符合预期）

	// 子类赋值运算符重载
	Student& operator = (const Student& s)
	{
		cout << "Student& operator= (const Student& s)" << endl;
		if (this != &s)
		{
			// 补充：子类operator=会隐藏父类operator=（同名成员隐藏），必须加父类作用域显式调用；
			// 若不调用，父类部分成员不会被赋值，仅子类部分赋值（逻辑不完整）
			Person::operator =(s); // 显式调用父类赋值运算符，初始化父类部分
			_num = s._num;         // 初始化子类部分
		}
		return *this;
	}

	// 子类析构函数
	~Student()
	{
		// 修正：子类析构函数会“隐藏”父类析构函数（编译器统一处理为~destructor）
		// 无需显式调用父类析构在子类的析构函数结束后自动调用
		cout << "~Student()" << endl;
	}
protected:
	int _num; // 学号
};

void Test()
{
	
	Student s1("jack", 18);
	//子类在实例化的时候不仅会调用自己的构造函数还会调用父类的构造函数
	//就是父类的部分调用父类的子类的部分调用子类的 析构也是一样的
	//在子类没法在构造函数的时候给父类的成员初始化 你可以再子类的构造函数调用父类的构造函数但没写也会自动调
	//但如果父类的构造函数并没有缺省值这时候你用子类实例化对象的时候就要再子类的构造函数里面显式调用父类
	//构造函数比如这里的jack就会调用Person(name) 但这个时候如果父类无缺省值就没法Student s1;这样初始化
	//因为子类会去调父类的构造函数而父类的没有缺省值需要参数 一般来说还是在子类手动调父类构造函数Person(name)
	//因为创建的是子类把参数给传到子类的构造函数里面了所以想要用参数来构造最好手动调用
	Student s2(s1);
	//和构造函数类似自己调用自己的
	//和构造函数一样没法在子类的拷贝构造里面拷贝构造父类的成员但是可以在子类调用父类的拷贝
	//在使用的时候: Person(s)这样就可以 我们之前学过子类和父类之间的赋值兼容规则所以在父类
	//的成员函数里面传子类的对象或者指针引用父类只对父类自己的成员做处理



	Student s3("rose", 17);


	s1 = s3;
	//赋值也是类似的要在子类里面调用父类的Person::operator =(s);

	



	// 不可继承类设计（补充C++11方案）
	// 原方案：父类构造函数私有（需配合静态函数创建对象，否则父类自身无法实例化）；
	// C++11更优方案：用final关键字（简洁安全），例：class Person final { ... }; // Person不能被继承(了解)

	// 友元函数（修正笔误+补充）
	// 友元函数不能被继承（友元关系是单向、非传递的）；若子类需让父类友元访问自身成员，需在子类中重新声明该友元

	// 静态成员（补充）
	// 静态成员（static修饰）会被继承，且属于“整个类家族”（父类+所有子类共享同一个静态成员）；
	// 例：父类static int count; 子类Student::count和Person::count是同一个变量（修改一个影响所有）
}

//复杂的菱形继承及菱形虚拟继承
//单继承：一个子类只有一个直接父类时称这个继承关系为单继承

//多继承：一个子类有两个或以上直接父类时称这个继承关系为多继承
//有两个类 class Student  class Teacher  这两个类有共同的子类class Assistant : public Student,public Teacher


//菱形继承是指 “一个顶层父类被两个子类分别继承，这两个子类再共同被一个孙子类继承” 的特殊多继承结构，
//其核心问题在于：一方面，由于两个子类均继承了顶层父类的成员，孙子类对象中会重复存储两份顶层父类的成员，
//造成内存上的数据冗余；另一方面，当孙子类访问顶层父类的成员时，
//编译器无法区分该成员是来自哪一个子类的继承路径，会产生访问的二义性，导致编译错误

//class Person
//{
//public:
//	string _name; // 姓名
//};
//class Student : public Person
//{
//protected:
//	int _num; //学号
//};
//class Teacher : public Person
//{
//protected:
//	int _id; // 职工编号
//};
//class Assistant : public Student, public Teacher
//{
//protected:
//	string _majorCourse; // 主修课程
//};
//void Test()
//{
//	// 这样会有二义性无法明确知道访问的是哪一个
//	Assistant a;
//	//a._name = "peter"; //这里就会产生二义性因为Student和Teacher里面都继承了Person里面的name
//	// 需要显示指定访问哪个父类的成员可以解决二义性问题，但是数据冗余问题无法解决
//	a.Student::_name = "xxx";
//	a.Teacher::_name = "yyy";
//}

//C++ 中可通过虚继承（virtual inheritance）让顶层父类成员在孙子类中仅存储一份且访问路径唯一，
//从而解决数据冗余与二义性问题。


class A
{
public:
	int _a;
};
// class B : public A
class B : virtual public A
{
public:
	int _b;
};
// class C : public A
class C : virtual public A
{
public:
	int _c;
};
class D : public B, public C
{
public:
	int _d;
};

void test_virtual()
{
	D d;
	d.B::_a = 1;
	d.C::_a = 2;
	d._b = 3;
	d._c = 4;
	d._d = 5;
}
















int main()
{
	
	// test_Person();
	// _Test();
	// Test_Person_Scope();
	// Test();

	return 0;
}